﻿/*
 
    This file is part of AnkhBG.

    AnkhBG is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AnkhBG is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with AnkhBG.  If not, see <http://www.gnu.org/licenses/>.
 
 */


using Glider.Common.Objects;
using System.Windows.Forms;

namespace AnkhBG
{
    
    public class QueueManager
    {
        #region Public Fields
        public Settings settings = Settings.Instance;


        // Check if we are queued by looking for the MiniMap-Icon
        public static bool IsQueued
        {
            get
            {
                GInterfaceObject frame = GContext.Main.Interface.GetByName("MiniMapBattlefieldFrame");
                return (frame != null && frame.IsVisible);
            }
        }

        // Check if we can enter a battleground by looking for the StaticPopup-frames
        public static bool CanEnter
        {
            get
            {
                for (int i = 1; i <= 4; ++i)
                {
                    GInterfaceObject obj = GContext.Main.Interface.GetByName("StaticPopup" + i.ToString());
                    if (obj == null || !obj.IsVisible)
                        continue;

                    GInterfaceObject text = obj.GetChildObject("StaticPopup" + i.ToString() + "Text");
                    if (text == null || !text.LabelText.StartsWith("You are now eligible to enter"))
                        continue;

                    return true;
                }

                return false;
            }
        }

        // Check if the battleground is over by looking for the Leave-Button
        public static bool CanLeave
        {
            get
            {
                GInterfaceObject obj = GContext.Main.Interface.GetByName("WorldStateScoreFrameLeaveButton");
                if (obj != null && obj.IsVisible)
                    return true;
                else
                    return false;
            }
        }
        #endregion


        #region Contructors

        public QueueManager()
        {
        }

        ~QueueManager()
        {
        }

        #endregion


        #region Public Methods
        // Accept the Queue-Dialog / Enter the battleground
        // returns an error-code (anything > 0 means an error occured)
        public int Enter()
        {
            if (CanEnter)
            {
                int popup = 0;
                for (int i = 1; i <= 4; ++i)
                {
                    GInterfaceObject obj = GContext.Main.Interface.GetByName("StaticPopup" + i.ToString());
                    if (obj == null || !obj.IsVisible)
                        continue;
                    GInterfaceObject text = obj.GetChildObject("StaticPopup" + i.ToString() + "Text");
                    if (text == null || !text.LabelText.StartsWith("You are now eligible to enter"))
                        continue;
                    popup = i;
                    break;
                }
                if (popup > 0)
                {
                    GInterfaceObject obj = GContext.Main.Interface.GetByName("StaticPopup" + popup.ToString() + "Button1");
                    if (obj != null && obj.IsVisible)
                    {
                        GContext.Main.EnableCursorHook();
                        obj.Hover();
                        obj.ClickMouse(false);
                        GContext.Main.DisableCursorHook();

                        return 0;
                    }
                    else
                        return 3;
                }
                else
                    return 2;
            }
            else
                return 1; // can't enter yet
        }

        // Leave the Queue
        // returns an error-code (anything > 0 means an error occured)
        public int Leave()
        {
            if (CanLeave)
            {
                GInterfaceObject obj = GContext.Main.Interface.GetByName("WorldStateScoreFrameLeaveButton");
                GContext.Main.EnableCursorHook();
                obj.Hover();
                obj.ClickMouse(false);
                GContext.Main.DisableCursorHook();
                return 0;
            }
            else
                return 1;
        }

        // Queue up
        // returns an error-code (anything > 0 means an error occured)
        public int Queue()
        {
                if (IsQueued)
                {
                    return 1; // is not queued
                }
                else
                {
                    GUnit[] units = GObjectList.GetUnits();
                    GUnit npc = null;
                    foreach (GUnit unit in units)
                    {
                        if (unit.IsMonster && !unit.IsDead) // yes NPCs are monsters... cruel truth
                        {
                            if (
                                    ( // find closest NPC
                                        (settings.QueueType == "closest" || settings.QueueType == "") &&
                                        (
                                            unit.Title == "Alterac Valley Battlemaster" ||
                                            unit.Title == "Arathi Basin Battlemaster" ||
                                            unit.Title == "Warsong Gulch Battlemaster" ||
                                            unit.Title == "Eye of the Storm Battlemaster"
                                        )
                                    ) ||
                                    ( // find specific battlemaster
                                        settings.QueueType == "specific" &&
                                        unit.Title.ToLower() == (settings.QueueBG + " battlemaster").ToLower()
                                    )
                                )
                            {
                                if (npc == null)
                                    npc = unit;
                                if (unit.DistanceToSelf < npc.DistanceToSelf)
                                    npc = unit;
                            }
                        }
                    }

                    if (npc == null)
                    {
                        if (settings.QueueType == "specific")
                        {
                            if (settings.QueueBG == "")
                                Main.Instance.Window.LogError("Please select a Battleground before starting.");
                            else
                                Main.Instance.Window.LogError("The battlemaster was not found.");
                        }
                        else
                            Main.Instance.Window.LogError("There are no NPCs around you!");

                        return 2;
                    }
                    else
                    {
                        GContext.Main.ClearTarget();

                        if (npc != null && !npc.IsValid)
                            npc = GObjectList.FindUnit(npc.GUID);

                        double approach_distance = 1.5f;
                        Main.Instance.Window.Log("Trying to approach " + npc.Name);
                        if (!npc.Approach(approach_distance))
                            GContext.Main.Debug("Couldn't approach " + npc.Name);

                        Main.Instance.Window.Log("Trying to talk to " + npc.Name + ".");
                        
                            for (int tries = 3; tries >= 0; --tries)
                            {
                                bool interacted = false;
                                if (npc != null && npc.IsValid)
                                {
                                    GContext.Main.EnableCursorHook();
                                    npc.Face();
                                    interacted = npc.Interact();
                                    GContext.Main.DisableCursorHook();
                                }
                                else if (!npc.IsValid)
                                    GContext.Main.Debug("AnkhBG: Unit was not valid, can't interact.");

                                if (interacted == false)
                                {
                                    GContext.Main.Debug("AnkhBG: Interaction failed, retrying in 2 minutes");
                                    Main.Instance.Window.LogError("Interaction failed, retrying in 2 minutes");
                                    //Starts timer to retry queueing in 120seconds
                                    //Main.Instance.Window.RetryInteractCd.Start();
                                    for (int delay = 120; delay > 0; delay--)
                                    {
                                        if (Main.Instance.running)
                                        {
                                            System.Threading.Thread.Sleep(1000);
                                            Main.Instance.Window.StatusText.Text = "Retrying interaction in: " + (delay - 1) + " seconds";
                                        }
                                        else
                                        {
                                            Main.Instance.Window.StatusText.Text = "Stopped";
                                            tries = -1;
                                        }
                                    }
                                    if (Main.Instance.running)
                                    {
                                        Main.Instance.Window.StatusText.Text = "Running";
                                        GContext.Main.Debug("AnkhBG: Retrying interaction");
                                        Main.Instance.Window.Log("Retrying interaction");
                                        return 0;
                                    }
                                    else
                                        tries = -1;
                                }
                                else
                                {
                                    // Try multiple times to interact if window wasn't found
                                    System.Threading.Thread.Sleep(1000);

                                    GInterfaceObject BattlefieldJoinFrame = GContext.Main.Interface.GetByName("BattlefieldFrameJoinButton");
                                    if (BattlefieldJoinFrame != null && BattlefieldJoinFrame.IsVisible)
                                    { // Join Battle
                                        GContext.Main.EnableCursorHook();
                                        BattlefieldJoinFrame.Hover();
                                        BattlefieldJoinFrame.ClickMouse(false);
                                        Main.Instance.Window.Log("We should be queued now.");
                                        GContext.Main.DisableCursorHook();
                                        GContext.Main.ClearTarget();
                                        break;
                                    }
                                    else
                                    { // Join-Button was not found
                                        if (tries == 0)
                                        {
                                            Main.Instance.Window.LogError("Couldn't find Battleground-Window.");
                                            return 4; // Join-Button was not found
                                        }
                                        else
                                        {
                                            System.Threading.Thread.Sleep(1000);
                                            continue; // we still have more tries
                                        }
                                    }
                                }
                            }
                        return 0; // no error
                    }
                }
        #endregion
        }
    }
}